﻿using System;
using System.Data;
using System.Drawing;
using System.IO;
using System.Xml;
using Infragistics.Win.UltraWinGrid;
using System.Collections.Generic;
using System.Collections;
using System.Linq;
using Home.Haushalt.Lib.Element;

namespace Home.Haushalt.Lib
{
    /// <summary>
    /// 
    /// </summary>
    public static class ExtClass
    {
        #region DataSet

        /// <summary>
        /// 
        /// </summary>
        /// <param name="ds"></param>
        /// <param name="xmlSourceName"></param>
        /// <param name="elementType"></param>
        /// <returns></returns>
        public static bool OpenXml(this DataSet ds, string xmlSourceName, Type elementType)
        {
            try
            {
                //ElementBase elementObj = ElementBase.Instantiate(elementTypeName);
                string schemacontent = ElementBase.Instantiate(elementType).ElementXsd;// elementType.GetStaticPropertyValue("ElementXsd").ToString(); //elementObj.GetElementXsd();

                MemoryStream schemaStream = new MemoryStream(System.Text.ASCIIEncoding.ASCII.GetBytes(schemacontent));
                MemoryStream xmldataStream = new MemoryStream(System.Text.UTF8Encoding.UTF8.GetBytes(global:: Home.Haushalt.Lib.Properties.Resources.ResourceManager.GetString(xmlSourceName)));

                ds.ReadXmlSchema(schemaStream);
                ds.ReadXml(xmldataStream);

                return true;
            }
            catch (Exception ex)
            {
                Journal.Add(typeof(ExtClass), "OpenXml(this DataSet ds, string xmlSourceName, string schemaName)", ex);

                return false;
            }
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="ds"></param>
        /// <param name="xmlFileName"></param>
        /// <param name="elementType"></param>
        /// <returns></returns>
        public static bool LoadXml(this DataSet ds, string xmlFileName, Type elementType)
        {
            try
            {
                MemoryStream schemaStream = null;

                string schemacontent = ElementBase.Instantiate(elementType).ElementXsd;

                schemaStream = new MemoryStream(System.Text.ASCIIEncoding.ASCII.GetBytes(schemacontent));

                ds.ReadXmlSchema(schemaStream);
                ds.ReadXml(xmlFileName);

                return true;
            }
            catch (Exception ex)
            {
                Journal.Add(typeof(ExtClass), "LoadXml(this DataSet ds, string xmlFileName, string schemaName)", ex);

                return false;
            }
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="ds"></param>
        /// <param name="filename"></param>
        /// <param name="elementType"></param>
        /// <param name="cry"></param>
        /// <returns></returns>
        public static bool LoadXml(this DataSet ds, string filename, Type elementType, HCryptography cry)
        {
            //ElementBase elementObj = ElementBase.Instantiate(elementTypeName);
            string schemacontent = ElementBase.Instantiate(elementType).ElementXsd; //elementType.GetStaticPropertyValue("ElementXsd").ToString(); //elementObj.GetElementXsd();

            try
            {
                MemoryStream schemaStream = new MemoryStream(System.Text.ASCIIEncoding.ASCII.GetBytes(schemacontent));
                ds.ReadXmlSchema(schemaStream);
            }
            catch (Exception ex)
            {
                Journal.Add(typeof(ExtClass), "LoadXml(this DataSet ds, string filename, string schemaName, HCryptography cry)", ex);
                return false;
            }

            if (!File.Exists(filename))
            {
                Journal.Add(typeof(ExtClass), ActionResult.Nok, "LoadXml(this DataSet ds, string filename, string schemaName, HCryptography cry): Datei [" + filename + "] ist nicht gefunden");
                return false;
            }

            byte[] daten = File.ReadAllBytes(filename);
            byte[] daten2 = new byte[0];

            try
            {
                daten2 = cry.Decrypt(daten);
                MemoryStream stream = new MemoryStream(daten2);
                ds.ReadXml(stream);
            }
            catch
            {
                Journal.Add(typeof(ExtClass), ActionResult.Hinweis, "LoadXml(this DataSet ds, string filename, string schemaName, HCryptography cry): Datei [" + filename + "] konnte nicht entschlüsselt werden");
                try
                {
                    MemoryStream stream = new MemoryStream(daten);
                    ds.ReadXml(stream);

                    Journal.Add(typeof(ExtClass), ActionResult.Hinweis, "LoadXml(this DataSet ds, string filename, string schemaName, HCryptography cry): Datei [" + filename + "] war nicht entschlüsselt. Verschlüsseln...");

                    ds.WriteXml(filename, cry);
                    Journal.Add(typeof(ExtClass), ActionResult.Hinweis, "LoadXml(this DataSet ds, string filename, string schemaName, HCryptography cry): Datei [" + filename + "] ist verschlüsselt");
                }
                catch (Exception ex)
                {
                    Journal.Add(typeof(ExtClass), "LoadXml(this DataSet ds, string filename, string schemaName, HCryptography cry)", ex);
                    return false;
                }
            }


            return true;
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="ds"></param>
        /// <param name="elementType"></param>
        /// <returns></returns>
        public static bool OpenSchema(this DataSet ds, Type elementType)
        {
            string schemacontent = ElementBase.Instantiate(elementType).ElementXsd;

            try
            {
                MemoryStream schemaStream = new MemoryStream(System.Text.ASCIIEncoding.ASCII.GetBytes(schemacontent));

                ds.ReadXmlSchema(schemaStream);

                return true;
            }
            catch (Exception ex)
            {
                Journal.Add(typeof(ExtClass), "OpenSchema(this DataSet ds, string schemaName)", ex);

                return false;
            }
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="ds"></param>
        /// <param name="filename"></param>
        /// <param name="cry"></param>
        /// <returns></returns>
        public static bool WriteXml(this DataSet ds, string filename, HCryptography cry)
        {
            try
            {
                MemoryStream stream = new MemoryStream();
                ds.WriteXml(stream);
                byte[] cryptedDs = cry.Encrypt(stream);

                FileStream fs = File.Open(filename, FileMode.OpenOrCreate, FileAccess.Write);
                fs.SetLength(0);
                fs.Write(cryptedDs, 0, cryptedDs.Length);
                fs.Close();

            }
            catch (Exception ex)
            {
                Journal.Add(typeof(ExtClass), "WriteXml(this DataSet ds, string filename, HCryptography cry)", ex);

                return false;
            }
            return true;
        }

        #endregion DataSet

        #region XmlDocument

        /// <summary>
        /// Open Xml and check via xsd file content
        /// </summary>
        /// <param name="doc"></param>
        /// <param name="xmlfileName"></param>
        /// <param name="xsdFileNames"></param>
        /// <returns></returns>
        public static bool LoadXml(this XmlDocument doc, string xmlfileName, params string[] xsdFileNames)
        {
            try
            {
                XmlReaderSettings settings = new XmlReaderSettings();
                settings.ValidationType = ValidationType.Schema;

                foreach (string xsdContentName in xsdFileNames)
                {
                    MemoryStream schemaStream = new MemoryStream(System.Text.ASCIIEncoding.ASCII.GetBytes(global:: Home.Haushalt.Lib.Properties.Resources.ResourceManager.GetString(xsdContentName)));
                    settings.Schemas.Add(null, XmlReader.Create(schemaStream));
                }

                MemoryStream xmlfileContentStream = new MemoryStream(System.Text.UTF8Encoding.UTF8.GetBytes(global:: Home.Haushalt.Lib.Properties.Resources.ResourceManager.GetString(xmlfileName)));
                XmlReader myReader = XmlReader.Create(xmlfileContentStream, settings);

                doc.Load(myReader);

                //Kommentare entfernen
                foreach (XmlNode node in doc.SelectNodes("//comment()"))
                {
                    node.ParentNode.RemoveChild(node);
                }


                return true;
            }
            catch (Exception ex)
            {
                Journal.Add(typeof(ExtClass), "LoadXml(this XmlDocument doc, string xmlfileName, params string[] xsdFileNames)", ex);

                return false;
            }
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="doc"></param>
        /// <param name="xmlfileName"></param>
        /// <param name="schemaContent"></param>
        /// <returns></returns>
        public static bool LoadXml(this XmlDocument doc, string xmlfileName, string schemaContent)
        {
            try
            {
                XmlReaderSettings settings = new XmlReaderSettings();
                settings.ValidationType = ValidationType.Schema;

                MemoryStream schemaStream = new MemoryStream(System.Text.ASCIIEncoding.ASCII.GetBytes(schemaContent));
                settings.Schemas.Add(null, XmlReader.Create(schemaStream));

                MemoryStream xmlfileContentStream = new MemoryStream(System.Text.UTF8Encoding.UTF8.GetBytes(global:: Home.Haushalt.Lib.Properties.Resources.ResourceManager.GetString(xmlfileName)));
                XmlReader myReader = XmlReader.Create(xmlfileContentStream, settings);

                doc.Load(myReader);

                //Kommentare entfernen
                foreach (XmlNode node in doc.SelectNodes("//comment()"))
                {
                    node.ParentNode.RemoveChild(node);
                }


                return true;
            }
            catch (Exception ex)
            {
                Journal.Add(typeof(ExtClass), "LoadXml(this XmlDocument doc, string xmlfileName, string schemaContent)", ex);

                return false;
            }
        }
        #endregion XmlDocument

        #region FROM STRING CONVERT METHODS

        /// <summary>
        /// 
        /// </summary>
        /// <param name="str"></param>
        /// <returns></returns>
        public static Color ToColor(this string str)
        {
            Color col = Color.Black;
            try
            {
                col = Color.FromName(str);
            }
            catch (Exception ex)
            {
                Journal.Add(col, ex);
            }

            return col;
        }


        /// <summary>
        /// 
        /// </summary>
        /// <param name="str"></param>
        /// <returns></returns>
        //public static Elements ToElements(this string str)
        //{
        //    return (Elements)Enum.Parse(typeof(Elements), str, true);
        //}

        /// <summary>
        /// 
        /// </summary>
        /// <param name="str"></param>
        /// <returns></returns>
        public static double ToDouble(this string str)
        {
            double result = 0;

            if (!double.TryParse(str, out result))
            {
                result = 0;
            }

            return result;
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="str"></param>
        /// <returns></returns>
        public static DateTime ToDateTime(this string str)
        {
            DateTime result = DateTime.MinValue;

            if (!DateTime.TryParse(str, out result))
            {
                result = DateTime.MinValue;
            }

            return result;
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="str"></param>
        /// <returns></returns>
        public static int ToInt(this string str)
        {
            int result = 0;

            if (!int.TryParse(str, out result))
            {
                result = 0;
            }

            return result;
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="str"></param>
        /// <returns></returns>
        public static bool ToBool(this string str, bool defaultValue)
        {
            bool result = defaultValue;
            try
            {
                result = Convert.ToBoolean(str);
            }
            catch (Exception ex)
            {
                Journal.Add(result, ex);
            }

            return result;
        }

        /// <summary>
        /// String mit Default-Separatoren ';', ',', '|' trennen
        /// </summary>
        /// <param name="str"></param>
        /// <returns></returns>
        public static List<string> ToList(this string str)
        {
            return str.ToList(new string[] { ";", ",", "|" }, false, new List<string>());
        }

        /// <summary>
        /// String mit Default-Separatoren ';', ',', '|' trennen
        /// </summary>
        /// <param name="str"></param>
        /// <param name="trim">Einzelne getrennte Items müssen von Anfangs- und End-Leerzeichen befreit werden</param>
        /// <returns></returns>
        public static List<string> ToList(this string str, bool trim)
        {
            return str.ToList(new string[] { ";", ",", "|" }, trim, new List<string>());
        }

        /// <summary>
        /// String mit Default-Separatoren ';', ',', '|' trennen
        /// </summary>
        /// <param name="str"></param>
        /// <param name="trim">Einzelne getrennte Items müssen von Anfangs- und End-Leerzeichen befreit werden</param>
        /// <param name="defaultValue"></param>
        /// <returns></returns>
        public static List<string> ToList(this string str, bool trim, List<string> defaultValue)
        {
            return str.ToList(new string[] { ";", ",", "|" }, trim, defaultValue);
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="str"></param>
        /// <param name="separators"></param>
        /// <param name="trim"></param>
        /// <param name="defaultValue"></param>
        /// <returns></returns>
        public static List<string> ToList(this string str, string[] separators, bool trim, List<string> defaultValue)
        {
            List<string> result = defaultValue;

            try
            {
                if (trim)
                {
                    result = str.Split(separators, StringSplitOptions.RemoveEmptyEntries).Select(item => item.Trim()).ToList<string>();
                }
                else
                {
                    result = str.Split(separators, StringSplitOptions.RemoveEmptyEntries).ToList<string>();
                }
            }
            catch
            {
                result = defaultValue;
            }

            return result;
        }

        /// <summary>
        /// returns true if the string can be parsed
        /// </summary>
        /// <param name="str"></param>
        /// <returns></returns>
        public static bool IsNumeric(this string str)
        {
            long result = 0;
            return long.TryParse(str, out result);
        }
        #endregion FROM STRING CONVERT METHODS

        #region ENUMERABLE

        /// <summary>
        /// 
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="source"></param>
        /// <param name="separator"></param>
        /// <returns></returns>
        public static string ToString<T>(this IEnumerable<T> source, string separator)
        {
            if (source == null)
                throw new ArgumentException("Parameter source can not be null.");

            if (string.IsNullOrEmpty(separator))
                throw new ArgumentException("Parameter separator can not be null or empty.");

            string[] array = source.Where(n => n != null).Select(n => n.ToString()).ToArray();

            return string.Join(separator, array);
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="source"></param>
        /// <param name="separator"></param>
        /// <returns></returns>
        public static string ToString(this IEnumerable source, string separator)
        {
            if (source == null)
                throw new ArgumentException("Parameter source can not be null.");

            if (string.IsNullOrEmpty(separator))
                throw new ArgumentException("Parameter separator can not be null or empty.");

            string[] array = source.Cast<object>().Where(n => n != null).Select(n => n.ToString()).ToArray();

            return string.Join(separator, array);
        }

        #endregion enumerable

        #region ENUMERATION

        /// <summary>
        /// 
        /// </summary>
        /// <param name="source"></param>
        /// <param name="enums"></param>
        /// <returns></returns>
        public static bool Any(this Enum source, params Enum[] enums)
        {
            return enums.Any(item => item.Equals(source));
        }

        #endregion enumeration


        #region FROM OBJECT CONVERT METHODS

        /// <summary>
        /// 
        /// </summary>
        /// <param name="obj"></param>
        /// <param name="defaultValue"></param>
        /// <returns></returns>
        public static bool ToBool(this object obj, bool defaultValue)
        {
            return (obj == null) ? defaultValue : obj.ToString().ToBool(defaultValue);
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="str"></param>
        /// <returns></returns>
        public static double ToDouble(this object obj)
        {
            return obj.ToString().ToDouble();
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="obj"></param>
        /// <returns></returns>
        public static DateTime ToDateTime(this object obj)
        {
            return obj != null ? obj.ToString().ToDateTime() : DateTime.MinValue;
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="obj"></param>
        /// <returns></returns>
        public static int ToInt(this object obj)
        {
            return obj.ToString().ToInt();
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="obj"></param>
        /// <returns></returns>
        //public static Elements ToElements(this object obj)
        //{
        //    return obj.ToString().ToElements();
        //}

        #endregion FROM OBJECT CONVERT METHODS

        #region FROM DATAROW CONVERT METHODS

        /// <summary>
        /// 
        /// </summary>
        /// <param name="sourceRow"></param>
        /// <param name="fieldName"></param>
        /// <returns></returns>
        public static int ToInt(this DataRow sourceRow, string fieldName)
        {
            return sourceRow[fieldName].ToString().ToInt();
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="sourceRow"></param>
        /// <param name="fieldName"></param>
        /// <returns></returns>
        public static double ToDouble(this DataRow sourceRow, string fieldName)
        {
            return sourceRow[fieldName].ToString().ToDouble();
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="sourceRow"></param>
        /// <param name="fieldName"></param>
        /// <returns></returns>
        public static DateTime ToDateTime(this DataRow sourceRow, string fieldName)
        {
            return sourceRow[fieldName].ToString().ToDateTime();
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="sourceRow"></param>
        /// <param name="fieldName"></param>
        /// <returns></returns>
        public static string ToString(this DataRow sourceRow, string fieldName)
        {
            return sourceRow[fieldName].ToString();
        }

        #endregion FROM DATAROW CONVERT METHODS

        #region DataRow

        /// <summary>
        /// 
        /// </summary>
        /// <param name="sourceRow"></param>
        /// <param name="shadowRow">Row, dessen Werte zu übernehmen sind</param>
        /// <returns>Einige Werte waren verändert</returns>
        public static bool ValuesEquals(this DataRow sourceRow, DataRow shadowRow)
        {
            for (int i = 0; i < shadowRow.Table.Columns.Count; i++)
            {
                if (sourceRow[i].ToString() != shadowRow[i].ToString())
                    return true;
            }
            return false;
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="sourceRow"></param>
        /// <param name="shadowRow">Row, dessen Werte zu übernehmen sind</param>
        /// <returns>Einige Werte waren verändert</returns>
        public static bool Update(this DataRow sourceRow, DataRow shadowRow)
        {
            return Update(sourceRow, shadowRow, sourceRow);
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="sourceRow"></param>
        /// <param name="shadowRow"></param>
        /// <param name="compareRow"></param>
        /// <returns></returns>
        public static bool Update(this DataRow sourceRow, DataRow shadowRow, DataRow compareRow)
        {
            bool changed = false;

            try
            {
                for (int i = 0; i < shadowRow.Table.Columns.Count; i++)
                {
                    if (compareRow[i].ToString() != shadowRow[i].ToString())
                    {
                        //Gültiges ID nicht überschreiben
                        if (shadowRow.Table.Columns[i].ColumnName.Equals(Posten.ELEMENTPROPERTY_ID) && !sourceRow[i].Equals(-1))
                            continue;

                        changed = true;

                        //Wert überschreiben
                        sourceRow[i] = shadowRow[i];
                    }
                }

                sourceRow.AcceptChanges();
                sourceRow.Table.AcceptChanges();
            }
            catch (Exception ex)
            {
                Journal.Add(typeof(ExtClass), "Update(this DataRow sourceRow, DataRow shadowRow)", ex);
            }

            return changed;
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="sourceRow"></param>
        /// <param name="shadowRow"></param>
        /// <returns></returns>
        public static List<string> GetChangedFields(this DataRow sourceRow, DataRow shadowRow)
        {
            List<string> changed = new List<string>();

            try
            {
                for (int i = 0; i < shadowRow.Table.Columns.Count; i++)
                {
                    if (sourceRow[i].ToString() != shadowRow[i].ToString())
                    {
                        changed.Add(shadowRow.Table.Columns[i].ColumnName);
                    }
                }
            }
            catch { }

            return changed;
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="sourceRow"></param>
        /// <returns></returns>
        public static DataRow Clone(this DataRow sourceRow)
        {
            DataRow clonedRow = sourceRow.Table.NewRow();

            foreach (DataColumn column in sourceRow.Table.Columns)
            {
                clonedRow[column] = sourceRow[column];
            }

            clonedRow[ElementBase.ELEMENTPROPERTY_ID] = -1;

            return clonedRow;
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="sourceRow"></param>
        /// <param name="targetTable"></param>
        /// <returns></returns>
        public static DataRow Copy(this DataRow sourceRow, DataTable targetTable)
        {
            DataRow copyRow = targetTable.NewRow();

            foreach (DataColumn column in sourceRow.Table.Columns)
            {
                copyRow[column.ColumnName] = sourceRow[column];
            }

            copyRow[ElementBase.ELEMENTPROPERTY_ID] = -1;

            return copyRow;
        }

        #endregion DataRow

        #region UltraGridRow

        /// <summary>
        /// 
        /// </summary>
        /// <param name="ultraGridRow"></param>
        /// <returns></returns>
        public static DataRow ToDataRow(this UltraGridRow ultraGridRow)
        {
            DataRow row = ((DataRowView)ultraGridRow.ListObject).Row;
            return row;
        }

        #endregion UltraGridRow

        #region TYPE

        /// <summary>
        /// 
        /// </summary>
        /// <param name="str"></param>
        /// <returns></returns>
        public static string ToElementName(this Type t)
        {
            return t.Name;
        }

        /*/// <summary>
        /// 
        /// </summary>
        /// <param name="type"></param>
        /// <param name="methodname"></param>
        /// <returns></returns>
        public static object GetStaticMethodValue(this Type type, string methodname)
        {
            MethodInfo mi = type.GetMethod(methodname);
            return mi.Invoke(null, null);
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="type"></param>
        /// <param name="propertyname"></param>
        /// <returns></returns>
        public static object GetStaticPropertyValue(this Type type, string propertyname)
        {
            PropertyInfo mi = type.GetProperty(propertyname);
            if(mi==null)
                mi = type.BaseType.GetProperty(propertyname);

            return (mi!=null)?mi.GetValue(null, null):null;
        }*/

        #endregion TYPE

        #region EXCEPTION

        /// <summary>
        /// Alle InnerException in string
        /// </summary>
        /// <param name="ex"></param>
        /// <param name="depth">Tiefe der Rekursion</param>
        /// <returns></returns>
        public static string GetFullExceptionText(this Exception ex, int depth)
        {
            if (ex == null)
                return "";

            string result = ex.Message;
            if (ex.InnerException != null && depth > 0)
            {
                result += "\n\n" + ex.InnerException.Message;
                result += GetFullExceptionText(ex.InnerException, --depth);
            }
            return result;
        }

        #endregion EXCEPTION


    }
}
